package org.fxcontainer.registry
{
	import com.developmentarc.core.datastructures.utils.HashTable;
	
	import flash.display.DisplayObject;
	
	import mx.containers.ViewStack;
	import mx.core.Container;
	import mx.events.ChildExistenceChangedEvent;
	
	import org.as3commons.logging.ILogger;
	import org.as3commons.logging.LoggerFactory;
	import org.fxcontainer.structure.IPage;
	import org.fxcontainer.utils.BrowserManagerHelper;
	
	/**
	 * Represents <code>IPage</code> registry to controll pages life cycles from one access point.<br>
	 * Extends <code>ViewStack</code> to support nested containers to be placed one above another.
	 * @author Izzet_Mustafayev
	 */
	public final class PageRegistry extends ViewStack
	{
		
		/**
		 * The pages holder. 
		 */
		private var _pages:HashTable;
		
		/**
		 * Current active <code>IPage</code> instance. 
		 */
		private var activePage:IPage;		
		
		/**
		 * The PageRegistry instance.
		 */
		static private var pageRegistryInstance:PageRegistry; 
		
		/**
		 * The logger instance. 
		 */
		static private var logger:ILogger = LoggerFactory.getClassLogger(PageRegistry);
		
		/**
		 * <code>PageRegistry</code> constructor.
		 */
		public function PageRegistry()
		{ 
			super();
			this._pages = new HashTable();
			this.addEventListener(ChildExistenceChangedEvent.CHILD_ADD, childAddHandler);
			pageRegistryInstance = this;
		}
		
		/**
		 * Creates <code>PageRegistry</code> as singleton instance. 
		 * @return created <code>PageRegistry</code>
		 */
		static private function get instance():PageRegistry
		{
			if (null == pageRegistryInstance){
				pageRegistryInstance = new PageRegistry();
			}
			return pageRegistryInstance;
		}
		
		/**
		 * Registers IPage within PageRegistry. 
		 * @param page the page to register 
		 */
		static public function register(page:IPage):void
		{
			instance.registerPage(page);
		}
		
		/**
		 * Process the page registering within PageRegistry.
		 * @param page the IPage to register.
		 */
		private function registerPage(page:IPage):void 
		{
			if(null == page) {
				throw Error("A page was not specified or is null.");
			}
			if (null == page.pageName()){
				throw Error("A page must have pagename property set.");
			}
			if(instance._pages.containsKey(page.pageName())){
				throw Error("A page with given name "+page.pageName()+" already exists.");
			}
			logger.debug("Register page with name: \"{0}\".", page.pageName());
			instance._pages.addItem(page.pageName(), page);
			if (page.isDefault()){
				instance.activatePage(page);
			}
		}
		
		/**
		 * Activates page with a given name. If page wont be found an Error will be thrown. 
		 * @param pageName the page name ti activate.
		 */
		static public function activate(pageName:String = null):void
		{
			if (null != pageName){
				var page:IPage = instance._pages.getItem(pageName) as IPage;
				instance.activatePage(page);
			}
			//activate default page
			if(null == pageName){
				var pageLen:int = instance._pages.length;
				var pages:Array = instance._pages.getAllItems();
				var isDefaultFound:Boolean = false;
				for(var i:int=0; i<pageLen; i++){
					var defpage:IPage = pages[i] as IPage;
					if(defpage.isDefault()){
						instance.activatePage(defpage);
						isDefaultFound = true;
						break;
					}
				}
				//activate first registered page as default
				if(!isDefaultFound){
					instance.activatePage(IPage(pages[0]));
				}
			}
			//set page title
			BrowserManagerHelper.setTitle(instance.activePage.pageTitle());
		}
		
		/**
		 * Process IPage activation. 
		 * @param page the page to activate
		 */
		private function activatePage(page:IPage):void
		{
			var needProcessing:Boolean = true;
			//need skip processing activation because current active page is same
			if (null != instance.activePage && page.pageName()==instance.activePage.pageName()){
				needProcessing = false;
			}
			if (null != instance.activePage && needProcessing){
				instance.activePage.deActivate();
			}
			if (null == instance.activePage){
				instance.activePage = page;
			}
			if (needProcessing){
				page.activate();
				instance.activePage = page;
				selectedChild = Container(page);
			}
			logger.debug("Page \"{0}\" was activated.", instance.activePage.pageName());
			BrowserManagerHelper.setTitle(instance.activePage.pageTitle());
		}
		
		/**
		 * The <code>ViewStack</code> container "add" event additional handler.<br> 
		 * Helps with autoregistering page as a <code>ViewStach</code> child component. 
		 * @param event the <code>ChildExistenceChangedEvent</code> event type
		 * 
		 */
		private function childAddHandler(event:ChildExistenceChangedEvent):void
		{
			var child:DisplayObject = event.relatedObject;
			//we accept only IPage implementations as a container child element
			if (!child is IPage){
				throw Error("Child elementy should be an IPage.");
			}
			
			instance.registerPage(IPage(child));
		}
		
		/**
		 * Retrieves <code>IPage</code> by the page name. 
		 * @param pageName the page name to retrieve <code>IPage</code> instance.
		 * @return the <code>IPage</code> instance.
		 */
		static public function getPage(pageName:String):IPage
		{
			var page:IPage = null;
			if (null != pageName){
				page= instance._pages.getItem(pageName) as IPage;
			}
			return page;
		} 
		
	}
}